#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Time    : 2021/1/23 11:35
# @Author  : Wang Feng
# @FileName: testcase.py
# @Software: PyCharm
import hashlib
import os
import shutil
import time
import zipfile

from flask import Blueprint, request, jsonify, make_response, send_file
from flask_restful import inputs

from app.models import TestCase
from app.settings import PROJECT_TMP_DIR, ZIP_TMP_DIR
from app.utils.e2tc_utils import E2TCUtils
from app.utils.project_utils import ProjectUtils
from app.utils.response_code import RET

testcase = Blueprint('testcase', __name__)


@testcase.route('/list', methods=['POST'])
def list_testcase():
    """
    获取测试用例列表
    :return:
    """
    epic = request.form.get('epic', type=str)
    feature = request.form.get('feature', type=str)
    story = request.form.get('story', type=str)
    title = request.form.get('title', type=str)
    test_case_id = request.form.get('test_case_id', type=str)
    has_test_script = request.form.get('has_test_script', type=inputs.boolean)
    marks = request.form.get('marks', type=str)
    page_num = request.form.get('page_num', 1, type=int)
    page_size = request.form.get('page_size', 10, type=int)
    filter_list = []
    if epic:
        filter_list.append(TestCase.epic.contains(epic))
    if feature:
        filter_list.append(TestCase.feature.contains(feature))
    if story:
        filter_list.append(TestCase.story.contains(story))
    if title:
        filter_list.append(TestCase.title.contains(title))
    if test_case_id:
        filter_list.append(TestCase.test_case_id.contains(test_case_id))
    if has_test_script in (True, False):
        filter_list.append(TestCase.has_test_script == has_test_script)
    if marks:
        filter_list.append(TestCase.marks.contains(marks))
    pagination = TestCase.query.filter(*filter_list).order_by(TestCase.id).paginate(page=page_num, per_page=page_size)
    total_page = pagination.pages
    count = pagination.total
    test_cases = pagination.items
    data = list(map(lambda test_case: test_case.to_dict(), test_cases))
    return jsonify(code=RET.OK, msg='查询成功', total_page=total_page, count=count, data=data)


@testcase.route('/upload', methods=['POST'])
def upload():
    """
    上传用例文件
    :return: json
    """

    # print(request.files)
    file = request.files['file']
    print(allowed_file(file.filename))
    # 上传文件为空
    if file is None:
        return jsonify(code=RET.PARAMERR, msg='参数file不能为空')
    # 上传文件不为xls、xlsx
    elif allowed_file(file.filename) is False:
        return jsonify(code=RET.PARAMERR, msg='只支持xls、xlsx文件上传')
    # print('file', type(file), file)
    # print(file.filename)  # 打印文件名
    else:
        f = file.read()  # 文件内容
        try:
            # excel用例文件解析
            test_cases = E2TCUtils.to_test_cases(f)
        except Exception as e:
            print(e)
            return jsonify(code=RET.SERVERERR, msg='文件解析失败')
        else:
            test_case_list = []
            for test_case in test_cases:
                test_case_full_name = '{feature}.{story}.{test}.{clazz}#{test}'.format(feature=test_case['feature'],
                                                                                       story=test_case['story'],
                                                                                       test=test_case['testCaseID'],
                                                                                       clazz=format_class_name(
                                                                                           test_case['testCaseID']))
                test_case_pk = md5(test_case_full_name)
                test_case_obj = TestCase.query.filter_by(test_case_pk=test_case_pk).first()
                if test_case_obj:
                    # 如果存在，更新用例
                    obj = test_case_obj
                else:
                    # 不存在，插入用例
                    obj = TestCase()
                obj.epic = test_case['epic']
                obj.feature = test_case['feature']
                obj.story = test_case['story']
                obj.title = test_case['title']
                obj.page = test_case['page']
                obj.marks = test_case['marks']
                obj.label = test_case['label']
                obj.is_auto = test_case['isAuto']
                obj.steps = test_case['steps']
                obj.expects = test_case['expects']
                obj.description = test_case['description']
                obj.prepare = test_case['prepare']
                obj.severity = test_case['severity']
                obj.test_case_id = test_case['testCaseID']
                obj.tester = test_case['tester']
                obj.test_case_full_name = test_case_full_name
                obj.test_case_pk = test_case_pk
                test_case_list.append(obj)
            if not TestCase.save_all(test_case_list):
                return jsonify(code=RET.DBERR, msg='数据插入失败')

            return jsonify(code=RET.OK, msg='上传成功')


# 允许上传的文件类型
ALLOWED_EXTENSIONS = {'xls', 'xlsx'}


def allowed_file(filename):
    """
    判断文件是否允许上传
    :param filename: 文件名
    :return: True、False
    """
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS


def md5(*args):
    m = hashlib.md5()
    for arg in args:
        part = arg.encode('utf-8')
        m.update(part)
    return m.hexdigest()


def format_class_name(class_str):
    """
    格式化类名
    :param class_str:
    :return:
    """
    class_name = ''
    for i in class_str.split('_'):
        class_name += i.capitalize()
    return class_name


def del_file(filepath):
    """
    删除某一目录下的所有文件或文件夹
    :param filepath: 路径
    :return:
    """
    del_list = os.listdir(filepath)
    for f in del_list:
        file_path = os.path.join(filepath, f)
        if os.path.isfile(file_path):
            os.remove(file_path)
        elif os.path.isdir(file_path):
            shutil.rmtree(file_path)


@testcase.route('/delete', methods=['POST'])
def delete():
    """
    删除测试用例
    :return:
    """
    id = request.form.get('id', type=int)
    if id:
        testcase = TestCase.query.get(id)
        # 判断数据不存在
        if not testcase:
            return jsonify(code=RET.NODATA, msg='数据不存在')
        # 删除失败
        if not testcase.delete():
            return jsonify(code=RET.DBERR, msg='删除失败')
        return jsonify(code=RET.OK, msg='删除成功')
    return jsonify(code=RET.PARAMERR, msg='参数错误: id不能为空')


@testcase.route('/export_project', methods=['POST'])
def export_project():
    """
    导出测试工程
    :return:
    """
    # 获取jsonlist参数
    testcases = request.json
    print(type(testcases))
    if not isinstance(testcases, list):
        return jsonify(code=RET.PARAMERR, msg='参数异常：必须为列表')
    elif len(testcases) == 0:
        return jsonify(code=RET.PARAMERR, msg='参数异常：列表数据不能为空')
    else:
        project_dir = PROJECT_TMP_DIR
        zip_dir = ZIP_TMP_DIR
        del_file(project_dir)
        del_file(zip_dir)
        try:
            ProjectUtils.create_project(testcases)
            zip_name = str(int(time.time())) + '.zip'
            zip_path = os.path.join(zip_dir, zip_name)
            with zipfile.ZipFile(zip_path, 'w') as target:
                for i in os.walk(project_dir):
                    for n in i[2]:
                        target.write(''.join((i[0], '\\', n)),
                                     arcname=''.join((os.path.relpath(i[0], project_dir), '\\', n)))
            response = make_response(send_file(zip_path))
            response.headers["Content-Disposition"] = "attachment; filename={zipf_name};".format(zipf_name=zip_name)
            # os.remove(zipf_path)
            return response
        except Exception as e:
            print(e)
            return jsonify(code=RET.SERVERERR, msg='内部错误：项目工程创建失败')
            # abort(400, msg='项目工程创建失败')
